package com.medistat.persistance.service.impl;

import java.util.Calendar;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.medistat.model.Doctor;
import com.medistat.model.FreeDay;
import com.medistat.model.StandardPersistentObject;
import com.medistat.model.WeekendDutiesInfo;
import com.medistat.model.Work;
import com.medistat.persistance.service.interfaces.Comparator;
import com.medistat.persistance.service.interfaces.DaoService;
import com.medistat.persistance.service.interfaces.Parameter;

public class DaoServiceImpl extends HibernateDaoSupport implements DaoService {

	@Override
	public <T extends StandardPersistentObject> void saveObject(T object) {
		getHibernateTemplate().save(object);
	}
	
	@Override
	public <T extends StandardPersistentObject> void saveOrUpdateAllObjects(List<T> objects) {
		getHibernateTemplate().saveOrUpdateAll(objects);
	}
	
	@Override
	public <T extends StandardPersistentObject> T getObject(Class<T> clazz, Long uid) {
		@SuppressWarnings("unchecked")
		T result = (T)getHibernateTemplate().get(clazz, uid);
		return result;
	}

	@Override
	public <T extends StandardPersistentObject> void deleteObject(T object) {
		getHibernateTemplate().delete(object);
		
	}

	@Override
	public <T extends StandardPersistentObject> void updateObject(T object) {
		getHibernateTemplate().update(object);
		
	}

	@Override
	public <T extends StandardPersistentObject> List<T> getAll(Class<T> clazz) {
		@SuppressWarnings("unchecked")
		List<T> result = getHibernateTemplate().loadAll(clazz);
		return result;
	}
	
	@Override
	public <T extends StandardPersistentObject> void saveAll(List<T> objects) {
		for(T object : objects) {
			getHibernateTemplate().saveOrUpdate(object);
		}
	}
	
	@Override
	public <T extends StandardPersistentObject> T findObjectByCriteria(Class<T> clazz, Parameter ...parameters) {
		List<T> objects = findObjectsByCriteria(clazz, parameters);
		if(objects==null) {
			return null;
		}
		return objects.get(0);
	}
	
	@Override
	public <T extends StandardPersistentObject> List<T> findObjectsByCriteria(Class<T> clazz, Parameter ...parameters) {
		DetachedCriteria criteria = DetachedCriteria.forClass(clazz);
		for(Parameter parameter : parameters) {
			if(Comparator.EQUAL.equals(parameter.getComparator())) {
				criteria.add(Restrictions.eq(parameter.getName(), parameter.getValue()));
			} else if(Comparator.GREATER_OR_EQUAL_THEN.equals(parameter.getComparator())) {
				criteria.add(Restrictions.ge(parameter.getName(), parameter.getValue()));
			} else if(Comparator.LOWER_OR_EQUAL_THEN.equals(parameter.getComparator())) {
				criteria.add(Restrictions.le(parameter.getName(), parameter.getValue()));
			} else if(Comparator.GREATER_THEN.equals(parameter.getComparator())) {
				criteria.add(Restrictions.gt(parameter.getName(), parameter.getValue()));
			} else if(Comparator.LOWER_THEN.equals(parameter.getComparator())) {
				criteria.add(Restrictions.lt(parameter.getName(), parameter.getValue()));
			} else if(Comparator.LIKE.equals(parameter.getComparator())) {
				criteria.add(Restrictions.like(parameter.getName(), parameter.getValue()));
			}
		}
		return findByCriteria(criteria);
	}
	
	@SuppressWarnings("unchecked")
	private <T extends StandardPersistentObject> List<T> findByCriteria(DetachedCriteria criteria) {
		List<T> result = getHibernateTemplate().findByCriteria(criteria);
		if(result.isEmpty()) {
			return null;
		}
		return result;
	}
	
	//Method is tested in persistenceServiceImplTest class
	@Override
	@SuppressWarnings("unchecked")
	public List<Work> getDutiesForYear(Integer year) {
		String HQL = "from Work w where w.schedule.year = :year and w.typeOfWork='DUTY'";
		Query query = getSession().createQuery(HQL);
		query.setParameter("year", year);
		return query.list();
	}

	//Method is tested in persistenceServiceImplTest class
	@Override
	@SuppressWarnings("unchecked")
	public FreeDay findFreeDayForDoctorOn(Calendar date, Doctor doctor) {
		String HQL = "from FreeDay f where f.person = :doctor and f.dateFrom <= :dateFrom and f.dateTo >= :dateTo";
		Query query = getSession().createQuery(HQL);
		query.setParameter("doctor", doctor);
		query.setParameter("dateFrom", date);
		query.setParameter("dateTo", date);
		List<FreeDay> freeDays= query.list();
		if(freeDays==null || freeDays.isEmpty()) {
			return null;
		}
		return freeDays.get(0);
	}

	@Override
	@SuppressWarnings("unchecked")
	public WeekendDutiesInfo getWeekendDutiesInfoForMaxCreationDateAndDoctor(Doctor doctor) {
		String HQL = "from WeekendDutiesInfo a where a.creationDate = (select max(b.creationDate) from WeekendDutiesInfo b where b.person = :doctor) and a.person = :doctor";
		Query query = getSession().createQuery(HQL);
		query.setParameter("doctor", doctor);
		List<WeekendDutiesInfo> weekendDutiesInfos= query.list();
		if(weekendDutiesInfos==null || weekendDutiesInfos.isEmpty()) {
			return null;
		}
		return weekendDutiesInfos.get(0);
	}
}
